Skip to content

feat(canvas): comment-mode annotation overlay with element and text targets#3599

Draft
adboio wants to merge 4 commits into
posthog-code/canvas-workspace-file-editingfrom
posthog-code/canvas-annotation-overlay
Draft

feat(canvas): comment-mode annotation overlay with element and text targets#3599
adboio wants to merge 4 commits into
posthog-code/canvas-workspace-file-editingfrom
posthog-code/canvas-annotation-overlay

Conversation

@adboio

@adboio adboio commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Problem

Canvas feedback is whole-document chat: describing the target in prose is the only way to point at something on the rendered canvas. There is no structured "annotate a specific part of the artifact" primitive.

Why

The second phase of making canvas iteration surgical (stacked on #3594's workspace-file editing): structured annotations that map onto targeted edits, and groundwork for plan-canvas review loops. Direction discussed in the linked task thread.

Changes

  • Comment mode: a host-authored overlay injected into the sandbox iframe (sandboxRuntime.ts, outside #root — agent-authored canvas code never sees it). Toolbar toggle → crosshair + hover highlight; click captures an element target, drag-select captures a text-range target. Targets are LLM-locatable rather than machine-precise: stable-attribute selector (allowlist + nth-of-type fallback, following the toolbar's product-tours inference in dependency-free form), bounded text snippet, attributes.
  • Pins + chips: queued annotations render as numbered pins in the canvas (re-anchored on scroll/resize/DOM mutation/remount) and as editable comment chips above the composer (canvasAnnotationsStore, per-canvas).
  • Delivery: on submit the queue folds into the generation instruction as a numbered [Annotations] block; the agent resolves each into a targeted edit of the checked-out scratch file via the feat(canvas): edit canvases as scratch files via canvas_checkout / canvas_publish #3594 loop. Two new schema-validated postMessage types each way; no new backend.

How did you test this code?

  • vitest: new [Annotations] prompt-block test; full canvas suites pass (core 94, ui 147).
  • tsc --noEmit clean on @posthog/core / @posthog/ui; biome clean on touched dirs.
  • Not yet run: the in-app e2e pass (comment mode → pins → annotation-driven edit) — the overlay isn't unit-testable per the canvas skill docs; gates undrafting alongside the base PR.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Created with PostHog Code

adboio added 4 commits July 20, 2026 11:59
Canvas generation previously required the agent to regenerate and emit the
entire React source every turn. Add a canvas_checkout / canvas_publish local
tool pair (available to both the Claude and Codex adapters) that moves the
file I/O tool-side: checkout writes the live source to a scratch path and
records the base version, the agent applies targeted edits with its native
file tools, and publish reads the file from disk and appends a version —
refusing when the canvas moved past the checkout base (concurrent edit or
undo) instead of clobbering it.

The generation prompt now routes through checkout → edit → publish and no
longer embeds the current source. Storage stays wholesale full-file
snapshots; a server-side base_version check on the desktop-fs PATCH remains
a follow-up.

Generated-By: PostHog Code
Task-Id: 2b3d176e-3023-41d2-92e8-81eda7c12a8c
…as action

canvas_publish now calls the desktop-fs canvas action, which owns version
composition server-side, passing the checkout's version as
expected_current_version_id so a stale publish is rejected atomically
(409 version_conflict) instead of guarded by a non-atomic tool-side
check-then-PATCH. Deletes the tool-side compose logic and the raw meta
PATCH; backends predating the guard field ignore it and publish
unguarded, so the tool degrades gracefully.

Server side: PostHog/posthog#72365.

Generated-By: PostHog Code
Task-Id: 2b3d176e-3023-41d2-92e8-81eda7c12a8c
…ools

The "do not regenerate wholesale" phrasing in the checkout tool description,
its runtime message, and the generation prompt warned against a workflow a
fresh agent never sees, and could bias against legitimately large rewrites.
The one forward-looking economy nudge (prefer targeted edits over rewriting
the whole file for a small change) stays in the authoring contract in
canvasTemplates.ts, stated once.

Generated-By: PostHog Code
Task-Id: 2b3d176e-3023-41d2-92e8-81eda7c12a8c
…argets

Canvas feedback was whole-document chat: describing the target in prose was
the only way to point at something. Add a comment mode to freeform canvases:
a host-authored overlay in the sandbox iframe captures element clicks and
text selections as structured, LLM-locatable targets (stable-attribute
selector, bounded text, attributes), queued annotations render as numbered
pins in the canvas and editable comment chips above the composer, and on
submit they fold into the generation instruction as a numbered
[Annotations] block the agent resolves into targeted edits of the
checked-out scratch file.

Selector inference follows the toolbar's product-tours approach (stable
attribute allowlist, nth-of-type fallback) in a dependency-free form —
precision is secondary since the consumer is the agent locating spots in
source it wrote itself.

Generated-By: PostHog Code
Task-Id: 2b3d176e-3023-41d2-92e8-81eda7c12a8c
@github-actions

Copy link
Copy Markdown

React Doctor found 2 issues in 2 files · 2 warnings.

2 warnings

src/features/canvas/freeform/FreeformCanvasView.tsx

src/features/canvas/freeform/FreeformGenerateBar.tsx

Reviewed by React Doctor for commit 3c61527.

@adboio
adboio force-pushed the posthog-code/canvas-workspace-file-editing branch 4 times, most recently from 061c5de to 0aca45b Compare July 20, 2026 20:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant